home *** CD-ROM | disk | FTP | other *** search
/ Gold Medal Software 2 / Gold Medal Software Volume 2 (Gold Medal) (1994).iso / prog / asm_0_m.arj / MDIR.ASM < prev    next >
Assembly Source File  |  1986-02-11  |  67KB  |  1,655 lines

  1. title     MDIR.ASM - Memory resident DIRectory
  2.  
  3. COMMENT |
  4.  
  5. I've long desired a memory resident directory routine.  This code began
  6. life as SD.ASM, whose original comments are reproduced below.
  7.  
  8. The routine will put the directory on the "alternate" screen if
  9. two monitors are available.  It does NOT check to see if the
  10. second monitor is actually installed.
  11.  
  12. Usage:
  13.           MDIR [2]
  14.  
  15. where the [2] indicates that both a color and a monochrome
  16. monitor are available on the system.  If you tell the routine
  17. that both are available, the directory will be printed to the
  18. monitor that is NOT currently being used.
  19.  
  20. If only ONE monitor is installed, or if MDIR is executed without
  21. the '2' on the command line, then the directory will be shown on
  22. the monitor that is currently being used.  If this is the case,
  23. MDIR will "save" the screen currently being used, and restore it
  24. when done.
  25.  
  26. To use MDIR once it has been installed, it is activated by
  27. pressing either the <Alt><8> or the <Alt><9> key combinations
  28. together (where the number keys are those above the alpha keys on
  29. the keyboard, NOT the ones from the numeric keypad).
  30.  
  31. If you press the <Alt><8> keys, the directory will be displayed
  32. in alphabetical order. If you press <Alt><9>, MDIR will prompt
  33. you for a "command line" to be used.  The command line can
  34. duplicate a command given to the DOS DIR command.  For example:
  35.  
  36. [assume the <Alt><9> keys have been pressed together]
  37.  
  38.         MDIR prompt             your response              results
  39. ╔════════════╧═════════════╗ ╔═════════╧══════════╗ ╔═════════╧══════════╗
  40. command line (/H for help):  *.*                    all files in the current
  41.                                                     directory
  42.                              \masm\files            all files in the sub-
  43.                                                     directory named
  44.                                                     \masm\files
  45.                              *.pas                  any file in the current
  46.                                                     directory with the
  47.                                                     extension .PAS
  48.                              \masm\files\*.arc      any file in the sub-
  49.                                                     directory named
  50.                                                     \masm\files with the
  51.                                                     extension .ARC
  52.                              b:*.*                  all files in the
  53.                                                     current directory
  54.                                                     on drive B:
  55.  
  56. In addition, there are several options, detailed below, that are
  57. triggered by the / switch.  /H given at the command line will list 
  58. the options, which deal with including hidden & subdirectory files, and
  59. with the way in which the file list is sorted.
  60.  
  61. The ability to handle path names was added to the original SD.ASM code.
  62. That approach was taken from:
  63.  
  64.      RED.ASM   John Dickinson, "REDirecting Your Files",
  65.                PC Magazine, Vol. 4, No. 4 (February 19, 1985)
  66.                Moving files between directories without
  67.                copy/erase
  68.  
  69.  
  70. CAVEATS:
  71.    1.  Because MDIR reads information from the disk, avoid
  72.        "triggering" this utility when an operating program
  73.        is working with the disks -- results can be
  74.        unpredictable (and fatal).
  75.    2.  The code is set up to prevent MDIR from being triggered twice
  76.        in a row -- a key other than the "trigger" keys must be pressed
  77.        between uses.
  78.    3.  The "trigger" keys are defined by EQUates near the top of the
  79.        code -- (see KEY1 and KEY2).  If they interfere as currently
  80.        defined, please reassign 'em.
  81.    4.  MDIR "sets up" the actual directory routines to use
  82.        one of the unused interrupts (currently INT 67h) -- please use
  83.        another interrupt if INT 67h interferes with any software that
  84.        you are currently using.  This interrupt approach was taken to:
  85.           a: allow the directory routine to read the keyboard without
  86.              calling its own routine;
  87.           b: to help isolate the directory routine from the effects
  88.              of pressing the <Alt><8 or 9> key combination again before
  89.              the directory routine has completed its work; and
  90.           c: it prevents MDIR from being REinstalled (MDIR will not
  91.              install if Int 67h is already in use).
  92.    5.  MDIR currently saves space for 256 directory entries
  93.        (see the variable DIRBUF at the end of the stay-resident code).
  94.        That's more than enough (by a factor of two) to display the files
  95.        in my most outrageous directory -- but be forewarned, DOS can
  96.        hold more than 256 entries in a subdirectory.  The problem with
  97.        increasing the storage space is that it requires 22 bytes per
  98.        entry -- and the storage space becomes part of the resident file. 
  99.        Thus, if we increased DIRBUF to 1024 entries, an extra 16,896
  100.        bytes of storage would stay resident when MDIR is installed.  I
  101.        prefer my resident utilities to be as small as possible (that's
  102.        why I detest stay-resident programs written in high-level
  103.        languages), so I've limited the space that mine requires.
  104.        The routine currently does not bother to check if you've got
  105.        more entries than space has been allocated for -- if you do,
  106.        you'll crash MDIR's stack (see below), and possibly memory
  107.        allocated to your operating program.  In any case, if you use
  108.        MDIR to display a directory with more entries than you've got
  109.        reserved, death and destruction (or at least a good
  110.        machine crash) can result.       
  111.    6.  The stack that MDIR uses when it is working is set at 150 words
  112.        (see STACKTOP at the end of the stay-resident code).  This
  113.        should be phenominally generous.
  114.    7.  MDIR does its best to trap disk errors -- it uses low-level
  115.        BIOS routines to initially find out if the requested disk
  116.        is ready.  This allows MDIR to bypass the dread DOS error
  117.        "disk not ready" -- which will cause a resident program to
  118.        crash the machine.  MDIR does NOT check to see if a hard drive
  119.        is ready.
  120.    8.  Some software stores information in the alternate pages of
  121.        the video memory IF you are using a color/graphics adaptor
  122.        (PC-Write, for example, stores its help screens in the memory
  123.        of the other c/g pages).  MDIR only saves the current video
  124.        page, so you can scramble help screens when MDIR switches
  125.        monitors.
  126.    9.  MDIR doesn't check if a drive has been ASSIGNed.  If you
  127.        request a directory for drive B:, MDIR will look for physical
  128.        drive B:.
  129.  
  130. I've used this routine with a variety of software, including:
  131.        Lotus' 123
  132.        PC-Write
  133.        PC-TALK
  134.        TURBO Pascal
  135.  
  136. This is one of several "two screen" utilities that I've been working on  --
  137. since I've got two monitors, I am tired of effectively wasting one.
  138.  
  139. MDIR may still have some bugs -- but then, you've got the source
  140. code, so please solve 'em (and let me know what you find).  It
  141. ain't perfect, but it's small and efficient, and it seems to work for me.
  142.  
  143. Please let me know about any bugs/comments that you have via
  144. Gene Plantz' IBBS, 312-882-4227.
  145.                                                      Mike Pechnyo
  146.                                                      ID1206
  147.  
  148. <><><><><><><><><><><><><><><><> SD.ASM COMMENTS <><><><><><><><><><><><><><><>
  149.  
  150.     SD [d:][filename[.ext]] [options]
  151.      [filespec] same as for DIR command
  152.      [options] * /A - List hidden files.
  153.                * /E - Without screen erase.
  154.                * /W - wait when screen full.
  155.                * /R - Include directory entries                     djm
  156.                * /M - Display Modified entries only                 djm
  157.                  /X - Sort by extension.
  158.                  /S - Sort by size.
  159.                  /D - Sort by date/time.
  160.                  /N - Do not sort, original order.
  161.                  /H - Help - only display options                   djm
  162.        Default = *.* sorted by name.ext with screen erase.
  163.        * - Option may be combined with other options.
  164.    This source file was created from an object file obtained
  165.  from Gene Plantz's BBS in Chicago. The original file name
  166.  was SD.HEX.  I then used DEBUG and CAPTURE to get the first
  167.  dis-assembly which  was then edited with WORDSTAR to create
  168.  a source that when assembled using MASM would duplicate the
  169.  original object file.
  170.    Comments have been added and I do hope they are helpful.
  171.  I have made several modifications to the first version and
  172.  am continuing to add comments.  This source file is an
  173.  excellent example for anyone wishing to learn 8086/8088
  174.  assembly language.  Use at your own risk and feel free to
  175.  share this file with your friends.
  176.    I certainly wish that John Chapman would publish his
  177.  source file.  His comments are sure to be more meaningful
  178.  than mine could ever be.  Some of the conversion routines
  179.  are very elegant, but difficult to understand.  As far as
  180.  I'm concerned, PRINTDD is magic.
  181.    Several modifications have been made.  They are:
  182.         1. Filespecs are processed like DIR does.
  183.         2. No sort option was added. /N
  184.         3. Pause when screen full option added. /P  changed to /W by DJM
  185.         4. Number of files found is printed.
  186.                                     Ted Reuss
  187.                                     Houston, TX
  188.     SDIR Version 2.2  The GETFREE Subroutine was updated for DOS 2.0
  189.     April 1, 1983   by   Jack Y. Fong
  190.     Changes are denoted by "JYF" at the end of changed lines.
  191.     I (Dave Mc Laughlin) have also made several modifications: (V 3.0)
  192.         Pause is now standard unless /P is entered to defeat
  193.         Color is now supported on color monitors
  194.         Free space is now reported at the bottom, along with
  195.           directory total (to give an idea of how many diskettes
  196.           may be required for backup)
  197.         Volume and current directory are shown on the top line
  198.           (my apologies to Capitol PC Club for removing their logo)
  199.         Modified files are shown with a + sign in place of the .
  200.         The /R option (show sub directory names) has been added
  201.         The /P option was changed to /W(ait) and /M (modified only) added
  202.  
  203.  
  204. <><><><><><><><><><><><><><> SD.ASM COMMENTS END <><><><><><><><><><><><><><><>
  205.  
  206.     All ANSI.SYS calls have been removed from SD.ASM (done to speed up
  207.       screen accesses)                                   mp   1-6-86
  208.  
  209. |
  210.  
  211.     SUBTTL  EQUATES & STRUCTURES
  212.     PAGE
  213. IF1
  214. DOSCALL MACRO       FUNC,PARM1
  215. .xcref
  216. F_C =       FUNC
  217. IFNB <PARM1>
  218. IF F_C EQ 2 OR (F_C GE 4 AND F_C LE 6) OR F_C EQ 14 OR F_C EQ 46
  219.     MOV     DL,PARM1
  220. ELSE
  221.     MOV     DX,OFFSET PARM1
  222. ENDIF
  223. ENDIF
  224.         MOV     AH,FUNC
  225.         INT     21H
  226. .cref
  227.         ENDM
  228. ENDIF
  229. .SALL   ;supress all macro expansions
  230. ;       PC-DOS INTERRUPT 21H FUNCTION CODES
  231. ;
  232. KEY1    equ     127     ; Alt 8 key (number key from on top of the keyboard)
  233. KEY2    equ     128     ; Alt 9 key (ditto)
  234.                         ; KEY1 will display a sorted directory of the
  235.                         ; current drive/subdirectory
  236.                         ; KEY2 will prompt for a "command line" which
  237.                         ; can be used to specify another subdirectory,
  238.                         ; drive, or files (wildcards in the file names
  239.                         ; are acceptable
  240. @CHROUT EQU     2       ;display char in DL
  241. @KEYIN  EQU     8       ;kybd input w/o echo
  242. @STROUT EQU     9       ;print string terminated with $
  243. @CKEYIN EQU     12      ;clr kybd bufr & do inp.func in AL
  244. @VOLLAB EQU     11h     ;search for first matching file, used for VOLUME LABEL
  245. @SRCH1  EQU     4Eh     ;search for first dir entry                  mp
  246. @SRCH2  EQU     4Fh     ;search for next dir entry                   mp
  247. @GETDSK EQU     25      ;get default disk drive
  248. @SETDTA EQU     26      ;set disk transfer addr
  249. @FATAD2 EQU     28      ;get FAT of drive # in DL
  250. @PARSEF EQU     41      ;parse filename
  251. @GETDTE EQU     42      ;get system date
  252. @GETTME EQU     44      ;get system time
  253. @DSKFSP EQU     36H     ;get disk free space                            JYF
  254. @GETVER EQU     30H     ;get version number                             JYF
  255. @GETDIR EQU     47H     ;get directory                                  djm
  256. CR      EQU     0DH     ;carriage return
  257. LF      EQU     0AH     ;line feed
  258. ; PC-DOS packed date   <yyyyyyym mmmddddd>
  259. P_DTE           RECORD  P_YR:7,P_MO:4,P_DY:5
  260. ; PC-DOS packed time   <hhhhhmmm mmmsssss>
  261. P_TME           RECORD  P_HR:5,P_MI:6,P_2S:5
  262. DIRNTRY STRUC               ;directory entry structure
  263. LNK     DW      0       ;ptr to next entry
  264. NAM     DB      8 DUP(0) ;filename
  265. SEP     DB      '.'      ;separator
  266. EXT     DB      3 DUP(0) ;extension
  267. TME     DW      0       ;time
  268. DTE     DW      0       ;date
  269. SZL     DW      0       ;low word of size
  270. SZH     DW      0       ;high word of size
  271. DIRNTRY ENDS
  272.  
  273. CODE_SEG     segment
  274.      assume  cs:CODE_SEG,ds:CODE_SEG
  275.      org     100h            ; COM program format
  276. BEGIN:     jmp     SWAP_VECTORS      ; Initialize vectors and attach to DOS
  277. ;
  278. getout:     nop
  279. immed:      db       0EAh
  280. redef16     label    word
  281. ROM_KB_INT     dd     ?      ; Double word to save address of
  282.                              ; ROM-BIOS keyboard interrupt
  283. INT24_LOC      dd     ?      ; to save address of INT24 location
  284. video_hold  dw 2000 dup(?)   ; storage to hold the old screen
  285. in_use      db 1
  286. shift_key   db 0
  287. old_equip   dw 0
  288. old_page    db 0
  289. old_mode    db 0
  290. old_pos     dw 0
  291. old_size    dw 0
  292. DIRWRK  DB      64 DUP (' ') ;directory work area                   djm
  293. ROOT    DB      '* * ROOT * *',18 DUP (' ') ;                       djm
  294. DIRSW   DB      0       ;0=this is not a directory entry            djm
  295. TOTL    DW      0       ;low order word of total size used          djm
  296. TOTH    DW      0       ;high order                                 djm
  297. C1LNK   DW      0       ;ptr to row 1, column 1
  298. C2LNK   DW      0       ;ptr to row 1, column 2
  299. NBRFILS DW      0       ;# of files or detail lines
  300. SRTFLG  DB      0       ;if = 0 then sort else no sort
  301. CLSFLG  DB      0       ;if = 0 then clear screen
  302. EXTFLG  DB      0       ;if <> 0 then sort by ext
  303. SIZFLG  DB      0       ;if <> 0 then sort by size
  304. PSEFLG  DB      0       ;if <> 0 then pause when screen is full
  305. DTEFLG  DB      0       ;if <> 0 then sort by date/time
  306. MODFLG  DB      0       ;if <> 0 then display modified only         djm
  307. OPTFLG  DB      0       ;if <> 0 then display options (no directory)djm
  308. command_len db  0
  309. command_line db 64 dup(0)       ; storage for "command line" typed in
  310. source_path  db 65 dup(0)
  311. DTA     DB      43 DUP(0)       ;Disk Transfer Area used
  312. old_FILNAME equ DTA+8
  313. old_FILTIME EQU DTA+30          ;directory search.
  314. old_FILSIZE EQU DTA+36
  315. old_FILATR  EQU DTA+19
  316. FILNAME EQU     DTA+30           ;by SRCHDIR for the
  317. FILTIME EQU     DTA+22          ;directory search.
  318. FILSIZE EQU     DTA+26
  319. FILATR  EQU     DTA+21
  320. other_dir   db  0          ; 0 indicates neither drive nor path specified
  321.                            ; 1 = path only specified
  322.                            ; 2 = drive (and maybe path) specified
  323. retries     db  0          ; # of times the disk was retried
  324. new_mask    db  0
  325. new_mode    dw  0       ; and for new mode, with video select chosen
  326. scrn_cols   db  80      ; screen columns available                        mp
  327. old_mask    dw  0FFFFh  ; old equipment flag
  328. DIRLNK  DW      DIRBUF  ;ptr to next opening in DIRBUF
  329. two_screens db  0       ; non-zero if more than one screen is available   mp
  330. PERMPSE  DB     1       ; permanent pause flag
  331. MAXDRIVE  db    0       ; number of floppy drives
  332. DIR_ATTR   db   16      ; directory attribute
  333.  
  334. LPERSCR EQU 25      ;Lines per screen
  335. LINCNT  DB      LPERSCR-4 ;Number of lines left
  336. PSEMSG  DB      'Strike a key when ready . . . $' ;           djm
  337. HDNG1   DB      'Vol: '
  338. VOLLOC  DB      13 DUP (' ')    ;put volume label here              djm
  339.         DB      'Dir: '
  340. DIRLOC  DB      27 DUP (' ')    ;put directory name here            djm
  341.         DB      3 DUP (' '),'Date: '    ;                           djm
  342. D_MM    DW      '00'            ;Month
  343.         DB      '/'
  344. D_DD    DW      '00'            ;Day
  345.         DB      '/'
  346. D_YY    DW      '00'            ;Year
  347.         DB      ' '
  348.         DB      'Time: '
  349. T_HH    DW      '00'            ;Hours
  350.         DB      ':'
  351. T_MM    DW      '00'            ;Minutes
  352.         DB      CR,LF
  353. CRLF    DB      CR,LF,'$'
  354. HDNG2   DB      'Filespec.ext  Bytes-  --Last Change--$'
  355.         DB      8 DUP(' ')
  356. SPACES  DB      '$'
  357. HDNG3   DB      ' File(s)',8 DUP (' '),'$'
  358. HDNG5   DB      ' Directory Total',9 DUP (' '),'$'      ;           djm
  359. HDNG6   DB      ' Free Space'
  360.         DB      CR,LF,'$'
  361. OPTHDG  DB      '  S O R T E D   D I R E C T O R Y',cr,lf
  362.         DB      CR,LF
  363.         DB      '     Display Options:',cr,lf
  364.         DB      '       /A  Include hidden files',cr,lf
  365.         DB      '       /R  Include directory names',cr,lf
  366.         DB      '       /M  Show only files that have been ',cr,lf
  367.         DB      '           modified since last backup',cr,lf
  368.         DB      '       /E  Don',39,'t erase screen before display',cr,lf
  369.         DB      '       /W  Wait when screen is full',cr,lf,cr,lf
  370.         DB      '      Sort Options  --  Sort by:',cr,lf
  371.         DB      '       /X  eXtension',cr,lf
  372.         DB      '       /S  Size',cr,lf
  373.         DB      '       /D  Date and time',cr,lf
  374.         DB      '       /N  No sort',cr,lf,'$'
  375.  
  376. error_msg   db  'There is a problem with drive '
  377. error_drive db  ' :.  (The door may be open).',13,10,10
  378. error_end   db  'Please fix the problem, and press any key '
  379.             db  ' .....  OR reboot the computer',13,10,'$'
  380. abort_message db 13,10,10,'MDIR is aborting ...',13,10,'$'
  381.  
  382.         SUBTTL  DISK TRANSFER AREA & FREE SPACE ENTRY DEFS
  383.         PAGE
  384. XFCB    DB      -1,7 DUP(0),11 DUP('?'),25 DUP(0)
  385. old_ATTRIB  EQU     XFCB+6          ;file attribute
  386. old_DRVNBR  EQU     old_ATTRIB+1    ;drive # (1=A, 2=B, etc.)
  387. ATTRIB  DB      0                ;file attribute
  388. DRVNBR  DB      0                ;drive # (1=A, 2=B, etc.)
  389. FREESPC DW      0               ;Free space entry.
  390.         DB      '*FREE SPACE*',4 DUP(0)
  391. LOSIZE  DW      0               ;of free space
  392. HISIZE  DW      0               ;of free space
  393. command_question db 'command line (/H for help): $'
  394. DosSSeg dw      0
  395. DosSP   dw      0
  396. command_location dw 0
  397. backslash   db  '\'
  398. stars   db      '*.*',0
  399. VALID_IN       db     'abcdefghijklmnopqrstuvwxyz,;=',9
  400. VALID_OUT      db     'ABCDEFGHIJKLMNOPQRSTUVWXYZ',4 dup(32)
  401. VALID_NUM      equ    $ - VALID_OUT + 1
  402.  
  403.  
  404. ; MDIR_INT intercepts the keyboard interrupt and shows the directory
  405. ;   if the KEY1 or KEY2 combination is pressed
  406. ;
  407.  
  408. MDIR_INT     proc     near
  409.      cmp    ah,0                      ; If Read Char request,
  410.      jne    bail_out                  ; check the in_use flag
  411.      cmp    cs:in_use,1               ; if MDIR is running, then use the
  412.      je     ChrRqst                   ; old handler to read the key
  413. bail_out:
  414.      jmp    getout                    ; else jump to the real routine
  415.  
  416. ChrRqst:
  417.      push    ds                       ; save just about every
  418.      push    bx                       ; register that anyone ever
  419.      push    cx                       ; heard of
  420.      push    dx
  421.      push    es
  422.      push    si
  423.      push    di
  424.      push    bp
  425.  
  426.      mov     bx,cs                    ; set up DS & ES
  427.      mov     ds,bx
  428.      mov     es,bx
  429.  
  430.      mov     cs:DosSSeg,ss
  431.      mov     cs:DosSP,sp
  432.  
  433.      cli
  434.  
  435.      mov     dx,ds                    ; set MDIR to use its own
  436.      mov     ss,dx                    ; stack
  437.      mov     sp,offset stacktop
  438.  
  439.      sti
  440.  
  441. do_interrupt:
  442.      int     67h             ; call the interrupt using the old AH val
  443.      cmp     al,0            ; is an extended key code returned?
  444.      jne     return
  445.      cmp     ah,KEY1         ; sorted dir of current subdir
  446.      je      check_use
  447.      cmp     ah,KEY2         ; prompt for command line
  448.      jne     return
  449. check_use:                   ; see if the in_use flag is on
  450.      cmp     in_use,1        ; in_use = 1, MDIR not running
  451.      jne     go_again        ; in_use <>1, MDIR currently working
  452.      mov     in_use,2
  453.  
  454.      mov     shift_key,ah    ; save the key code used to call MDIR
  455.  
  456.      call    get_mdir        ; and do the directory work
  457. go_again:
  458.      mov     ah,0            ; setup to read the keyboard again
  459.      jmp     short do_interrupt   ; and loop back.  This will not "release"
  460.                                   ; until a key other than KEY1 or KEY2 has
  461.                                   ; been pressed (that new key will be
  462.                                   ; returned to whatever program was running
  463.                                   ; when MDIR interrupted.
  464.  
  465. return:
  466.      mov     in_use,1        ; MDIR is done
  467.  
  468.      cli
  469.  
  470.      mov     ss,cs:DosSSeg       ; reset the stack to wherever it was
  471.      mov     sp,cs:DosSP         ; originally
  472.  
  473.      pop     bp                  ; and pop all of the saved registers
  474.      pop     di                  ; (the new AX value is passed)
  475.      pop     si
  476.      pop     es
  477.      pop     dx
  478.      pop     cx
  479.      pop     bx
  480.      pop     ds
  481.  
  482.      iret                         ; and complete the interrupt call
  483. mdir_int     endp
  484.  
  485. GET_MDIR proc near               ; show the directories
  486. ;
  487. ; set up the displays
  488. ;
  489.      call     init_video
  490. ;
  491. ; call directory routines
  492. ;
  493. DO_DIRECTORIES:
  494.      call     clear_vars      ; clear any significant variables
  495.      cmp      shift_key,KEY2  ; which key was pressed?
  496.      je       A0a             ; if KEY2, get a command line sequence
  497.      call     get_drive       ; else process current directory
  498.      mov      command_location,offset stars
  499.      jmp      short A0b
  500. A0a:
  501.      call     get_command     ; get and process the command line
  502. A0b:
  503.      cmp      retries,2
  504.      jb       A0c             ; did the disk still fail?
  505.      mov      si,offset abort_message
  506.      call     show_line
  507.      jmp      short A99a      ; show the pause message
  508. A0c:
  509.      call     srchdir         ;Search directory
  510.      cmp      SRTFLG,0        ;Check if any sort
  511.      jz       A1              ; option selected.
  512.      call     lnkdirb         ;Leave in original
  513.      jmp      short A2        ; directory order.
  514. A1:  call     srtdirb         ;Sort by major key
  515. A2:  mov      al,optflg       ;See if only options wanted         djm
  516.      or       al,al           ;See if H request for help          djm
  517.      jz       A3              ;Wasn't                             djm
  518.      mov      si,offset OPTHDG
  519.      call show_line
  520.      jmp      short A99       ;get out                            djm
  521. A3:  call     getfree         ;Get free space
  522.      call     spltlst         ;Set up for 2 columns
  523.      call     prthdng         ;Print headings
  524.      call     prtdrvr         ;Print detail lines
  525.      call     prtnfls         ;Print # of files
  526. ;
  527. A99:
  528.      cmp      two_screens,1    ; if there are two screens, then reset
  529.      je       A100             ; the mode
  530. A99a:
  531.      mov      si,offset PSEMSG ;Display pause message.
  532.      call     show_line
  533.      mov      ah,0             ;Specify input function
  534.      int      67h              ;Wait for key press
  535. A100:
  536.      call     restore_video    ; restore the screens
  537.      ret
  538. GET_MDIR endp
  539.  
  540. INIT_VIDEO proc near
  541. ;
  542. ; Save the current cursor position
  543. ;
  544.      mov      ah,3            ; Call Func 3 of Int 10H
  545.      mov      bh,0            ; to read cursor position
  546.      int      10h             ; (page zero for color screen)
  547.      mov      old_size,cx     ; cursor start and stop lines
  548.      mov      old_pos,dx      ; cursor row, column
  549. ;
  550. ; get the video status
  551. ;
  552.      mov      ah,0fh
  553.      int      10h             ; get video mode
  554.      mov      old_mode,al     ; video mode
  555.      mov      old_page,bh     ; current page
  556.      cmp      al,7            ; are we currently in monochrome mode?
  557.      jne      SAVE_SCREEN
  558.      cmp      old_size,0607h  ; was the old cursor incorrectly set
  559.                               ; to the color cursor's size?
  560.      jne      SAVE_SCREEN
  561.      mov      old_size,0B0Ch  ; start on 11, end on line 12
  562.                               ; note: DOS does not always set the proper cursor
  563.                               ; size upon startup - so this code catches the
  564.                               ; problem.  See PC TECH JOURNAL, Dec., 1985,
  565.                               ; "The Dashed Cursor", Paul Pierce, p. 47.
  566. ;
  567. ; save the screen data
  568. ;
  569. SAVE_SCREEN:
  570.      push     ds
  571.      mov      ax,0b000h
  572.      cmp      old_mode,7      ; Did we switch from mono?
  573.      je       COPY_SCREEN     ; Yes, move data from mono
  574.      mov      ax,0b800h
  575.      add      ah,old_page     ; c/g card page addresses are:
  576.                               ; Mode  0  Address  B800
  577.                               ;       1           B900
  578.                               ;       2           BA00
  579.                               ;       3           BB00
  580. COPY_SCREEN:
  581.      mov      ds,ax
  582.      xor      si,si           ; Start at zero offset
  583.      push     cs              ; mov from DS:SI to ES:DI
  584.      pop      es
  585.      mov      di,offset VIDEO_HOLD
  586.      mov      cx,2000         ; 2000 chars + attrs per screen
  587.      cld                      ; Make sure move is 'forward'
  588. rep  movsw                    ; Move Words with string instruction
  589.      pop      ds
  590. ;
  591. ; Screen switch routine - Establish calling argument (AL) for Int 10h
  592. ;
  593.      cmp      two_screens,1    ; if there are two screens, then go through
  594.      je       switch_screens1  ; the mode setting exercise
  595.  
  596.      mov      ah,6             ; else clear the window
  597.      mov      al,0
  598.      mov      bh,7
  599.      xor      cx,cx            ; upper left corner
  600.      mov      dh,24            ; row, column of lower right corner
  601.      mov      dl,79
  602.      int      10h
  603.      mov      ah,2
  604.      xor      dx,dx
  605.      mov      bh,old_page
  606.      int      10h              ; set cursor to 0,0 position
  607.      jmp      short INIT_DONE  ; since there was only one screen,
  608.                                ; the setup is done
  609.  
  610. switch_screens1:               ; set up the second screen
  611.      push     ds
  612.      xor      ax,ax           ; set DS to 0
  613.      mov      ds,ax
  614.      mov      bx,word ptr ds:[410h]  ; Current equipment flag to BX
  615.      pop      ds
  616.      mov      old_equip,bx
  617.      mov      cx,bx           ; Make a copy of the equipment flag in CX
  618.      and      cx,30h          ; Extract screen information
  619.      xor      bx,cx           ; Erase current screen information in BX
  620.      or       bx,20h          ; Set BX to color 80x25
  621.      mov      al,2            ; Set AL for B&W 80x25 in Int 10h
  622.      cmp      cx,30h          ; Is current mono?
  623.      je       SET_MODE1       ; Yes, switch to color
  624.      or       bx,30h          ; No, set BX for monochrome
  625.      mov      al,7            ; Set AL for monochrome in Int 10h
  626. SET_MODE1:
  627.      push     ds
  628.      push     ax
  629.      xor      ax,ax           ; set DS to 0
  630.      mov      ds,ax
  631.      mov      word ptr ds:[410h],bx  ; Write BX to equipment flag
  632.      pop      ax
  633.  
  634.      xor      ah,ah           ; Use Func 0 of Int 10h to
  635.      int      10h             ; change screen parameters
  636.      pop      ds
  637. INIT_DONE:
  638.      ret
  639. INIT_VIDEO endp
  640.  
  641. RESTORE_VIDEO proc near        ; return the video to its original mode
  642.      cmp      two_screens,1    ; if there are two screens, then reset
  643.      jne      short skip_page  ; the mode
  644.  
  645.      mov      bx,old_equip
  646.      push     ds               ; save DS for use again
  647.      xor      ax,ax            ; set DS to 0
  648.      mov      ds,ax
  649.      mov      word ptr ds:[410h],bx  ; restore the original equipment flag
  650.      pop      ds
  651.  
  652.      mov      al,old_mode     ; restore the original video mode
  653.      xor      ah,ah           ; Use Func 0 of Int 10h to
  654.      int      10h             ; change screen parameters
  655.  
  656.      cmp      old_mode,7      ; is the screen monochrome?
  657.      je       skip_page
  658.      mov      ah,5
  659.      mov      al,old_page
  660.      int      10h             ; set the video page to the old value
  661. ;
  662. ; After screens are switched back, return the screen data
  663. ;
  664. skip_page:
  665.      mov      ax,0b000h
  666.      cmp      old_mode,7      ; Did we switch back to mono?
  667.      je       COPY_BACK       ; yes, so copy to the mono screen
  668.      mov      ax,0b800h
  669.      add      ah,old_page     ; restore to the proper video page
  670. COPY_BACK:
  671.      mov      es,ax
  672.      xor      di,di           ; Start at zero offset
  673.      push     cs              ; mov from DS:SI to ES:DI
  674.      pop      ds
  675.      mov      si,offset VIDEO_HOLD
  676.      mov      cx,2000         ; 2000 chars + attrs per screen
  677.      cld                      ; Make sure move is 'forward'
  678. rep  movsw                    ; Move Words with string instruction
  679. ;
  680. ; Restore Cursor position
  681. ;
  682.      mov      dx,old_pos      ; restore the cursor position from the stack
  683.      mov      ah,2            ; Use Func 2 of Int 10h to restore
  684.      mov      bh,old_page
  685.      int      10h
  686. ;
  687. ; Restore Cursor size
  688. ;
  689.      mov      cx,old_size     ; restore the cursor size from the stack
  690.      mov      ah,1            ; Use Func 1 of Int 10h to set cursor
  691.      int      10h
  692. ;
  693.      ret
  694. RESTORE_VIDEO endp
  695.  
  696. SHOW_LINE proc near          ; a simple-minded procedure to duplicate
  697.                              ; the INT 21h function to print a string
  698.                              ; terminated by a $.  The routine uses
  699.                              ; the low-level BIOS Int 10h call rather
  700.                              ; than the DOS call.
  701.      push     ax
  702. print_loop:
  703.      mov      al,byte ptr ds:[si]
  704.      cmp      al,'$'
  705.      je       print_done
  706.      call     show_char
  707.      inc      si
  708.      jmp      short print_loop
  709. print_done:
  710.      pop      ax
  711.      ret
  712. SHOW_LINE endp
  713.  
  714. SHOW_CHAR proc near           ; print a character using BIOS Int 10h
  715.                               ; character should be in AL
  716.      mov      ah,0Eh
  717.      int      10h             ; tty write function
  718.      ret
  719. SHOW_CHAR endp
  720.  
  721. CLEAR_VARS proc near          ; clear all pertinent variables, and
  722.                               ; set initial values where needed.
  723.      push    cs
  724.      pop     es               ; set up the extra segment
  725.      cld                      ; and make all moves forward
  726.      mov     di,offset dirwrk ; fill DIRWRK with spaces
  727.      mov     al,' '
  728.      mov     cx,64            ; bytes to clear
  729. rep  stosb
  730.      mov     di,offset dirsw
  731.      mov     cx,offset new_mask
  732.      mov     bx,offset dirsw
  733.      sub     cx,bx
  734.      xor     ax,ax
  735. rep  stosb
  736.      mov     di,offset xfcb   ; and clear a series of variables to 0
  737.      inc     di
  738.      mov     cx,offset freespc
  739.      mov     bx,di
  740.      sub     cx,bx
  741.      xor     ax,ax
  742. rep  stosb
  743.      mov     di,offset xfcb   ; fill the FCB with question marks (?)
  744.      add     di,8
  745.      mov     al,'?'
  746.      mov     cx,11
  747. rep  stosb
  748.      mov     di,offset volloc  ; and fill the headings with spaces
  749.      mov     cx,13
  750.      mov     al,' '
  751. rep  stosb
  752.      mov     di,offset dirloc
  753.      mov     cx,27
  754.      mov     al,' '
  755. rep  stosb
  756.      mov     t_mm,'00'        ; clear the header variables used
  757.      mov     t_hh,'00'
  758.      mov     d_dd,'00'
  759.      mov     d_mm,'00'
  760.      mov     d_yy,'00'
  761.      mov     scrn_cols,80     ; screen columns available
  762.      mov     old_mask,0FFFFh  ; old equipment flag
  763.      MOV     ax,OFFSET DIRBUF ;Point to DIRBUF
  764.      mov     dirlnk,ax        ; reset the pointer
  765.  
  766.      mov     LINCNT,LPERSCR-4 ;Reset to # lines/screen
  767.      mov     al,PERMPSE
  768.      mov     PSEFLG,al
  769.      ret
  770. CLEAR_VARS endp
  771.  
  772. GET_DRIVE proc near           ; get the current drive
  773.      doscall @GETDSK          ;AL <- default disk
  774.      inc     al               ;Increment drive #
  775.      mov     DRVNBR,al        ;Save drive #
  776.      call    check_drive
  777.      ret
  778. GET_DRIVE endp
  779.  
  780. CHECK_DRIVE proc near         ; see if the requested drive (number
  781.                               ; stored in DRVNBR is available.
  782.                               ; Use the BIOS interrupt to avoid
  783.                               ; DOS errors, and read a sector from
  784.                               ; within the FAT (which ought to be
  785.                               ; good if the disk is to work)
  786.      push    bx
  787.      push    cx
  788.      push    dx
  789.      cli
  790.      mov     al,DRVNBR
  791.      cmp     al,MAXDRIVE
  792.      ja      drive_checked    ; don't check if we're looking at a hard drive
  793.                               ; assume the hard drive is OK and ready
  794. begin_check:
  795.      mov     cx,3
  796. recheck_loop:
  797.      push    cx
  798.      mov     bx,offset DIRBUF   ; temporarily use the directory buffer
  799.                                 ; ES:BX point to the input buffer
  800.      mov     ah,2               ; read sectors into memory
  801.      mov     al,1               ; # of sectors to read
  802.      mov     ch,0               ; track
  803.      mov     cl,4               ; sector to read -- somewhere in the FAT
  804.      mov     dh,0               ; head #
  805.      mov     dl,DRVNBR
  806.      dec     dl                 ; so that drive # is in the form 0=A, 1=B
  807.      int     13h
  808.      pop     cx                 ; restore the count
  809.      cmp     ah,0
  810.      je      drive_checked      ; CF=1 means that the read failed, so retry
  811.      mov     ah,0
  812.      int     13h                ; reset the drive
  813.      loop    recheck_loop
  814.      inc     RETRIES
  815.      cmp     RETRIES,1          ; see how many times we've been here
  816.                                 ; IBM recommends trying a BIOS call 3 times
  817.                                 ; to make sure the disk is ready.  We
  818.                                 ; give one retry if it doesn't work the
  819.                                 ; first time.  If it doesn't work the
  820.                                 ; second time, MDIR aborts.
  821.      ja      drive_checked
  822.      mov     al,DRVNBR
  823.      add     al,'@'
  824.      mov     byte ptr error_drive,al
  825.      mov     si,offset error_msg  ; show the error message
  826.      call    show_line
  827.      mov     ah,0
  828.      int     67h                ; wait for a keypress
  829.      jmp     short begin_check
  830. drive_checked:
  831.      sti
  832.      pop     dx
  833.      pop     cx
  834.      pop     bx
  835.      ret
  836. CHECK_DRIVE endp
  837.  
  838. GET_COMMAND proc near               ; get a "command line" in response
  839.                                     ; to KEY2
  840.                                     ; limitted editing (backspace and left
  841.                                     ; arrow only both delete the last
  842.                                     ; character in the command line)
  843.                                     ; is supported
  844.      push    cs
  845.      push    cs
  846.      pop     ds
  847.      pop     es
  848.  
  849.      mov     si,offset command_question
  850.      call    show_line
  851.  
  852.      mov     di,offset command_line
  853.      cld
  854. arg_loop:
  855.      mov     ah,0
  856.      int     67h             ; read the keyboard
  857.      cmp     al,0
  858.      jnz     check_key
  859.      cmp     ah,'K'          ; was the left arrow pressed?
  860.      jne     arg_loop        ; nope, so try again
  861.      mov     al,8            ; it was the left arrow, so process it as a
  862.                              ; backspace
  863. check_key:
  864.      cmp     al,13           ; was the carriage return hit?
  865.      je      arg_done        ; if yes, the command line is done
  866.  
  867.      mov     ah,0Eh          ; if not, print the character using teletype mode
  868.      int     10h             ; tty write function
  869.      cmp     al,8            ; backspace ???
  870.      jne     other_key       ; no, so process the key
  871.      dec     command_len     ; yes, so decrement the counters,
  872.      dec     di              ; and write a space + backspace
  873.      mov     al,' '          ; over the character on the
  874.      mov     ah,0eh          ; screen
  875.      int     10h
  876.      mov     al,8
  877.      mov     ah,0eh
  878.      int     10h
  879.      jmp     short arg_loop
  880. other_key:
  881.      inc     command_len
  882.      stosb                   ; save the byte
  883.      jmp     short arg_loop
  884. arg_done:
  885.      mov     al,0            ; put a zero byte at the end of the string
  886.      stosb
  887.      mov     si,offset crlf  ; and space down twice
  888.      call    show_line
  889.      mov     si,offset crlf
  890.      call    show_line
  891.  
  892. CHECK_CMD_LINE:
  893.      mov     si,offset command_len   ; command line length
  894.      xor     ch,ch                   ; Zero CH
  895.      mov     cl,[si]                 ; Move byte count to CL
  896.      cmp     cl,0
  897.      jnz     PARSE_CMD_LINE          ; If CX is zero, there are no parameters
  898.      jmp     BLANK_EXIT              ; so handle this as if it were a KEY1 call
  899.  
  900. PARSE_CMD_LINE:
  901.      mov     dx,cx                   ; Save byte count in dx
  902.      inc     si                      ; Point to parameter area
  903.      mov     di,si                   ; Copy SI to DI for cleanup routine
  904.      cld                             ; Set direction flag to forward
  905.  
  906. CLEAN_PARMS:     ; Change valid delimiters to blanks, lower to upper case
  907.      lodsb                           ; Load each character to AL
  908.      push    di                      ; Save DI on stack
  909.      mov     di,offset VALID_IN      ; Point to table of valid inputs
  910.      push    cx                      ; Save CX on stack
  911.      mov     cx,VALID_NUM            ; Set CX to number of inputs to look for
  912. repne  scasb                         ; See if any are in AL
  913.      jcxz    CLEAN_END               ; If not, change nothing
  914.      mov     bx,VALID_NUM            ; Set up BX to point to valid output
  915.      sub     bx,cx                   ; This will leave BX one off
  916.      mov     al,VALID_OUT [bx - 1]   ; Load the valid output to AL
  917. CLEAN_END:
  918.      cmp     al,'/'                  ; is it the switch character?
  919.      jne     NOT_SWITCH              ; (the switch character will
  920.      pop     cx                      ; terminate the directory request
  921.      pop     di                      ; of the command line)
  922.      mov     al,0                    ; make the first command an ASCIIZ
  923.      stosb
  924.      mov     si,di                   ; point to the rest of the command line
  925.      call    getargs                 ; and process the switch commands
  926.      sub     dx,cx                   ; correct the string length
  927.      jmp     short SWITCH_FOUND
  928. NOT_SWITCH:
  929.      pop     cx                      ; Restore CX
  930.      pop     di                      ; Restore DI
  931.      stosb                           ; Store modified AL back to command line
  932. loop     CLEAN_PARMS                 ; Loop until CX is zero
  933. ;
  934. SWITCH_FOUND:
  935.      mov     cx,dx                   ; Restore number of bytes in cmd line
  936.      cmp     cx,0
  937.      jne     PARSE_BLANKS
  938.      jmp     BLANK_EXIT
  939. PARSE_BLANKS:                        ; remove blanks
  940.      mov     al,' '                  ; Set up to scan for first non-blank
  941.      mov     di,offset command_line  ; Set DI to command_line
  942. FIND_PARMS:     ; Start looking for parameters, load to program storage
  943. repe     scasb                       ; Scan while blanks
  944.      jnz     FIX_DI                  ; if we've scanned everything
  945.      jmp     BLANK_EXIT
  946. FIX_DI:
  947.      dec     di                      ; Adjust it to first non-blank byte
  948.      mov     si,di
  949.      inc     cx                      ; Adjust CX to compensate
  950.  
  951.      mov     di,offset source_path   ; Set DI to parameter hold area
  952. STORE:
  953.      lodsb                           ; Load each byte to AL
  954.      cmp     al,' '                  ; Is it a blank?
  955.      jz      END_STORE               ; Yes, end of this parameter
  956.      stosb                           ; No, store the byte to hold area
  957. END_STORE:
  958.      loopnz  STORE                   ; Keep looking  {must come after labelled
  959.                                      ; jump to properly decrement CX}
  960.      mov     al,0
  961.      stosb                           ; make the string an ASCIIZ
  962.      mov     other_dir,1             ; a path was specified
  963.      mov     di, offset source_path
  964.      mov     command_location,di
  965.      cmp     byte ptr [di],'\'       ; a '\' only indicates the root dir
  966.      jne     NOT_ROOT                ; has been requested
  967.      inc     di
  968.      cmp     byte ptr [di],0         ; is this just the root?
  969.      jne     NOT_ROOT
  970.      mov     si,offset stars         ; get ready to move bytes
  971.      mov     cx,4
  972. rep  movsb                           ; and copy the \*.* string
  973.      call    get_drive
  974.      jmp     short NOT_DIR
  975. NOT_ROOT:
  976.      mov     di, offset source_path + 1
  977.      cmp     byte ptr [di],':'       ; has a drive been specified?
  978.      je      DRIVE_SPECD
  979.      call    get_drive
  980.      jmp     short COMMAND_GIVEN
  981. DRIVE_SPECD:
  982.      mov     other_dir,2             ; a drive (and maybe a path) has been
  983.      dec     di                      ; specified
  984.      mov     al,byte ptr [di]
  985.      sub     al,'@'
  986.      mov     DRVNBR,al              ; save the drive number
  987.      call    check_drive            ; see if it is a legitimate drive
  988.      cmp     retries,1              ; did the check fail?
  989.      ja      NOT_DIR
  990.      inc     di
  991.      inc     di
  992.      cmp     byte ptr [di],0        ; is the third byte the end-of-string?
  993.      jne     COMMAND_GIVEN
  994.      mov     si,offset backslash    ; get ready to move bytes
  995.      mov     cx,5
  996. rep  movsb                          ; and copy the \*.* string
  997. COMMAND_GIVEN:
  998.      xor     cx,cx
  999.      mov     cl,DIR_ATTR            ; see if a subdirectory only was
  1000.                                     ; requested.  (With the DOS DIR
  1001.                                     ; command, if \MASM\FILES is a
  1002.                                     ; subdirectory, then 'DIR \MASM\FILES'
  1003.                                     ; will display all the files contained
  1004.                                     ; in that subdirectory.
  1005.  
  1006.      DOSCALL @SETDTA,DTA            ;Set DTA for dir. search
  1007.      mov     ah,@srch1
  1008.      mov     dx,command_location
  1009.      int     21h
  1010.      or      al,al
  1011.      jnz     NOT_DIR
  1012.      mov     al,DIR_ATTR
  1013.      cmp     FILATR,al        ;did we get a directory back?
  1014.      je      IS_DIR
  1015.      mov     other_dir,0      ; no, so clear the flag
  1016.      jmp     short NOT_DIR
  1017. IS_DIR:
  1018.      mov     al,0
  1019.      mov     cx,65            ; > DOS command line
  1020.      mov     di,offset source_path
  1021. repne    scasb                ; look for the end-of-string
  1022.      dec     di               ; adjust DI to point to the last character
  1023.      mov     si,offset backslash    ; get ready to move bytes
  1024.      mov     cx,5
  1025. rep  movsb                          ; and copy the \*.* string
  1026.  
  1027. NOT_DIR:
  1028.      ret
  1029.  
  1030. BLANK_EXIT:                    ; if a real command line wasn't specified,
  1031.                                ; then use the default '*.*'
  1032.      mov     command_location,offset stars   ; default command line
  1033.      call    get_drive         ; get the current drive
  1034.      ret                       ; and bail out, because no parameters
  1035.                                ; were entered
  1036. GET_COMMAND endp
  1037.  
  1038. GETARGS PROC    NEAR          ; get any arguments after the / switch
  1039.                               ; SI needs to point to the ASCIIZ argument string
  1040. B2:  CMP      BYTE PTR [SI],0
  1041.      je       b99
  1042.      MOV      AL,[SI]         ;AL <- option letter
  1043.      mov      byte ptr [si],' '  ; replace the character with a space
  1044.      CMP      al,'/'
  1045.      Je       B11             ;If not a slash
  1046.      AND      AL,0DFH         ;Force to upper-case
  1047.      CMP      AL,'A'          ;Hidden & system files?
  1048.      JNZ      B31             ;Nope, try next one.                djm
  1049.      OR       ATTRIB,2+4      ;Hidden & system                    djm
  1050.      jmp      short B11
  1051. B31: CMP      AL,'R'          ;directory entries?                 djm
  1052.      JNZ      B3              ;Nope, try next one.                djm
  1053.      OR       ATTRIB,10H      ;Directory                          djm
  1054.      jmp      short B11
  1055. B3:  CMP      AL,'E'          ;Without screen erase?
  1056.      JNZ      B4              ;Nope, try next one.
  1057.      MOV      CLSFLG,AL
  1058.      jmp      short B11
  1059. B4:  CMP      AL,'S'          ;Sort by size?
  1060.      JNZ      B5              ;Nope, try next one.
  1061.      MOV      SIZFLG,AL
  1062.      jmp      short B11
  1063. B5:  CMP      AL,'D'          ;Sort by date/time?
  1064.      JNZ      B6              ;Nope, try next one.
  1065.      MOV      DTEFLG,AL
  1066.      jmp      short B11
  1067. B6:  CMP      AL,'X'          ;Sort by extension?
  1068.      JNZ      B7              ;Nope, try next one.
  1069.      MOV      EXTFLG,AL
  1070.      jmp      short B11
  1071. B7:  CMP      AL,'N'          ;Original order?
  1072.      JNZ      B8              ;Nope, try next one.
  1073.      MOV      SRTFLG,AL
  1074.      jmp      short B11
  1075. B8:  CMP      AL,'W'          ;Wait when screen full?
  1076.      JNZ      B9              ;Nope, try next one.
  1077.      MOV      PSEFLG,AL       ;                                   djm
  1078.      jmp      short B11
  1079. B9:  CMP      AL,'M'          ;Just show modified entries?        djm
  1080.      JNZ      B10             ;Nope, try next one.                djm
  1081.      MOV      MODFLG,AL       ;                                   djm
  1082.      jmp      short B11
  1083. B10: CMP      AL,'H'          ;Just show options?                 djm
  1084.      JNZ      B11             ;Nope, try next one                 djm
  1085.      MOV      OPTFLG,AL       ;                                   djm
  1086. B11: INC      SI              ;Point to next char
  1087.      jmp      B2              ;Test for another param.
  1088.  
  1089. B99: RET
  1090. GETARGS ENDP
  1091.  
  1092. SRCHDIR PROC    NEAR           ; do the actual directory search
  1093.      MOV     BYTE PTR old_ATTRIB,8   ;get volume label           djm
  1094.      mov     al,DRVNBR
  1095.      mov     byte ptr old_DRVNBR,al
  1096.      DOSCALL @SETDTA,DTA                                         djm
  1097.      DOSCALL @VOLLAB,XFCB    ;get volume label                   djm
  1098.      OR      AL,AL           ;found it?                          djm
  1099.      JNZ     C11             ;none found                         djm
  1100.      MOV     SI,OFFSET old_FILNAME ;source field                 djm
  1101.      MOV     DI,OFFSET VOLLOC        ;put in vol label           djm
  1102.      MOV     CX,11           ;length                             djm
  1103.      CLD                     ;clear direction flag               djm
  1104.      REPZ    MOVSB           ;do it                              djm
  1105. c11: xor     cx,cx
  1106.      mov     cl,ATTRIB
  1107.      DOSCALL @SETDTA,DTA     ;Set DTA for dir. search
  1108.      mov     ah,@srch1
  1109.      mov     dx,command_location
  1110.      int     21h
  1111. C1:  OR      AL,AL
  1112.      JZ      C21             ;found                              djm
  1113.      JMP     C2              ;not found - quit looking           djm
  1114. C21: mov     si,offset FILNAME
  1115.      MOV     AL,[SI]         ;get first byte of entry            djm
  1116.      CMP     AL,'.'          ;see if sub directory entry         djm
  1117.      JNZ     C211            ;no - process
  1118.      jmp     C41
  1119. C211:
  1120.      MOV     BX,DIRLNK       ;BX <- base of DIRBUF
  1121.      LEA     DI,[BX].NAM
  1122.      MOV     CX,13           ;13 bytes in the filename
  1123.      CLD
  1124.      mov     al,' '
  1125. rep  stosb                   ; fill the filename with blanks
  1126.  
  1127.      lea     di,[bx].sep
  1128.      MOV     AL,FILATR       ;load file attributes               djm
  1129.      TEST    AL,20h          ;see if attr bit set                djm
  1130.      JZ      C3              ;no                                 djm
  1131.      MOV     BYTE PTR [DI],'+'       ;                           djm
  1132.      JMP     SHORT C4        ;                                   djm
  1133. C3:  ; not modified - now see if /M set                          djm
  1134.      CMP     MODFLG,0        ;see if /M set                      djm
  1135.      JNE     C41             ;wasn't, so skip this entry         djm
  1136.      TEST    AL,10H          ;see if directory entry             djm
  1137.      JZ      C31             ;no                                 djm
  1138.      MOV     BYTE PTR [DI],'-'       ;store a minus for dir      djm
  1139.      JMP     SHORT C4        ;                                   djm
  1140. C31: MOV     BYTE PTR [DI],'.' ; Store a period
  1141. C4:
  1142.      LEA     DI,[BX].NAM     ; start at the filename again
  1143.      mov     si,offset FILNAME
  1144.      MOV     CX,SIZE NAM
  1145.      inc     cx              ; search 9 characters for the period, if needed
  1146. C22: lodsb
  1147.      cmp     al,0
  1148.      je      C4c             ; quit if the end of the string
  1149.      cmp     al,'.'
  1150.      je      C23             ; found the period in the file name
  1151.      stosb                   ;Move filename to DIRBUF
  1152.      loop    C22
  1153. C23:
  1154.      lea     di,[bx].ext
  1155.      MOV     CX,SIZE EXT
  1156. C4a: lodsb
  1157.      cmp     al,0
  1158.      je      C4c             ; found the period in the file name
  1159.      stosb                   ;Move ext to DIRBUF
  1160.      loop    C4a
  1161. C4c:
  1162.      lea     di,[bx].tme
  1163.      MOV     SI,OFFSET FILTIME
  1164.      MOVSW                   ;Move time to DIRBUF
  1165.      MOVSW                   ;Move date to DIRBUF
  1166.      MOV     SI,OFFSET FILSIZE
  1167.      MOV     AX,[SI]         ;get number for size addition       djm
  1168.      ADD     TOTL,AX         ;add                                djm
  1169.      MOVSW                   ;Move size to DIRBUF
  1170.      MOV     AX,[SI]         ;get high order                     djm
  1171.      ADC     TOTH,AX         ;add                                djm
  1172.      MOVSW
  1173.      ADD     BX,SIZE DIRNTRY ;Point to next entry
  1174.      MOV     DIRLNK,BX       ;Save ptr
  1175.      INC     NBRFILS         ;Increment file count
  1176. C41: DOSCALL @SRCH2          ;Search for next file
  1177.      JMP     C1              ;Loop for next one
  1178. C2:  RET
  1179. SRCHDIR ENDP
  1180.  
  1181. SRTDIRB PROC    NEAR    ;Sorts directory entries in DIRBUF
  1182.      MOV     DI,OFFSET DIRBUF ;Point to DIRBUF
  1183. D1:  CMP     DI,DIRLNK       ;Are there anymore?
  1184.      JNC     D8              ;NO, exit
  1185.      MOV     SI,OFFSET C1LNK ;Start with column 1 ptr
  1186. D2:  MOV     BX,SI
  1187.      MOV     SI,[BX]         ;SI<-ptr to next entry
  1188.      OR      SI,SI
  1189.      JZ      D7              ;if link=0
  1190.      MOV     AX,SI
  1191.      MOV     DX,DI
  1192.      XOR     CL,CL           ;CL <- 0
  1193.      CMP     CL,SIZFLG
  1194.      JNZ     D5              ;If sort by size
  1195.      CMP     CL,DTEFLG
  1196.      JNZ     D4              ;If sort by date/time
  1197.      CMP     CL,EXTFLG
  1198.      JNZ     D3              ;If sort by ext
  1199.      LEA     SI,[SI].NAM
  1200.      LEA     DI,[DI].NAM
  1201.      MOV     CX,1+SIZE NAM+SIZE EXT  ;# of bytes
  1202.      JMP     SHORT D6
  1203. D3:  LEA     SI,[SI].EXT     ;Sort by extension
  1204.      LEA     DI,[DI].EXT
  1205.      MOV     CX,SIZE EXT     ;# of bytes
  1206.      JMP     SHORT D6
  1207. D4:  LEA     SI,[SI].DTE     ;Sort by date/time
  1208.      LEA     DI,[DI].DTE
  1209.      MOV     CX,2            ;# of words
  1210.      STD
  1211.      REPZ    CMPSW
  1212.      MOV     DI,DX
  1213.      MOV     SI,AX
  1214.      JBE     D2
  1215.      JMP     SHORT D7
  1216. D5:  LEA     SI,[SI].SZH     ;Sort by size
  1217.      LEA     DI,[DI].SZH
  1218.      MOV     CX,2            ;# of words
  1219.      STD
  1220.      REPZ    CMPSW
  1221.      MOV     DI,DX
  1222.      MOV     SI,AX
  1223.      JBE     D2
  1224.      JMP     SHORT D7
  1225. D6:  CLD                     ;Sort by name.ext
  1226.      REPZ    CMPSB
  1227.      MOV     DI,DX
  1228.      MOV     SI,AX
  1229.      JBE     D2
  1230. D7:  MOV     [DI],SI
  1231.      MOV     [BX],DI
  1232.      ADD     DI,SIZE DIRNTRY ;Point to next entry
  1233.      JMP     D1
  1234. D8:  RET
  1235. SRTDIRB ENDP
  1236.  
  1237. ; LNKDIRB - LINKS ENTRIES IN DIRBUF
  1238. LNKDIRB PROC    NEAR            ;LINK ENTRIES IN DIRBUF
  1239.      MOV     DI,OFFSET DIRBUF
  1240.      MOV     C1LNK,DI       ;Point to 1st entry
  1241.      MOV     CX,NBRFILS      ;Set loop counter
  1242.      DEC     CX
  1243. LNK1:
  1244.      MOV     BX,DI
  1245.      ADD     DI,SIZE DIRNTRY ;Offset to next entry
  1246.      MOV     [BX],DI         ;Store ptr
  1247.      LOOP    LNK1            ;Link next entry
  1248.      MOV     [DI],CX         ;Last ptr <- null
  1249.      RET
  1250. LNKDIRB ENDP
  1251.  
  1252. ; SPLTLST - SPLITS LINKED LIST IN HALF
  1253. SPLTLST PROC    NEAR
  1254.      MOV     CX,NBRFILS      ;Get # of entries
  1255.      SAR     CX,1            ; and divide by 2
  1256.      JZ      F2              ;if NBRFILS < 2
  1257.      ADC     CL,0            ;Account for odd #
  1258.      MOV     BX,OFFSET C1LNK
  1259. F1:  MOV     BX,[BX]         ;Chain thru list to
  1260.      LOOP    F1              ; last row of column 1.
  1261.      MOV     AX,[BX]         ;Get ptr to 1st row of col 2
  1262.      MOV     C2LNK,AX        ; C2LNK <- R1,C2 ptr
  1263.      MOV     [BX],CX         ;Last row of col 1 <- null
  1264. F2:  RET
  1265. SPLTLST ENDP
  1266.  
  1267. GETFREE PROC    NEAR         ;cluster = allocation unit
  1268.      MOV     DL,DRVNBR       ;Get drive #
  1269.      PUSH    DS              ;Save DS
  1270.      DOSCALL @DSKFSP         ;get disk free space                JYF
  1271.      MUL     BX              ;AX (sectors/clustor) * BX (free cluJYF
  1272.      MOV     DX,AX           ;                                   JYF
  1273.      MUL     CX              ;AX * CX (bytes/clustor)            JYF
  1274.                              ;                                   JYF
  1275.      POP     DS              ;Restore DS
  1276.      MOV     LOSIZE,AX       ;Save the 32 bit
  1277.      MOV     HISIZE,DX       ; binary free space
  1278.      RET
  1279. GETFREE ENDP
  1280.  
  1281. PRTHDNG PROC        NEAR
  1282.      DOSCALL @GETDTE ; CX<-year, DH<-month, DL<-day
  1283.      MOV     AL,DH
  1284.      AAM
  1285.      XCHG    AL,AH
  1286.      OR      D_MM,AX         ;Fold into month
  1287.      MOV     AL,DL
  1288.      AAM
  1289.      XCHG    AL,AH
  1290.      OR      D_DD,AX         ;Fold into day
  1291.      MOV     AX,CX
  1292.      SUB     AX,1900
  1293.      AAM
  1294.      XCHG    AL,AH
  1295.      OR      D_YY,AX         ;Fold into year
  1296.      DOSCALL @GETTME ; CH<-hours, CL<-minutes
  1297.      MOV     AL,CH           ;AL<-binary hours
  1298.      AAM                     ;Convert AL to two
  1299.      XCHG    AL,AH           ; BCD digits in AX.
  1300.      OR      T_HH,AX         ;Fold into hours
  1301.      MOV     AL,CL           ;AL<-binary minutes
  1302.      AAM                     ;Convert AL to two
  1303.      XCHG    AL,AH           ; BCD digits in AX.
  1304.      OR      T_MM,AX         ;Fold into minutes
  1305.  
  1306.      cld                     ; make all moves forward
  1307.  
  1308.      mov     di,offset dirloc
  1309.      mov     si,offset command_line
  1310.      cmp     other_dir,2     ; are both drive & dir specified?
  1311.      je      G11
  1312.  
  1313.      mov     al,DRVNBR       ; if drive & path weren't spec'd
  1314.      add     al,'@'          ; put 'em into DIRLOC
  1315.      stosb
  1316.      mov     al,':'
  1317.      stosb
  1318.  
  1319.      cmp     other_dir,1     ; was only the dir specified?
  1320.      je      G11
  1321.  
  1322.      MOV     DL,DRVNBR       ;set dl to current drive            djm
  1323.      MOV     SI,OFFSET DIRWRK ;point to work area                djm
  1324.      DOSCALL @GETDIR         ;get directory                      djm
  1325.      MOV     AL,[SI]         ;get 1st char                       djm
  1326.      CMP     AL,0            ;see if no directory name           djm
  1327.      JE      G11a            ;this is root directory             djm
  1328.      mov     al,'\'
  1329.      stosb
  1330.      jmp     short G11
  1331. G11a:
  1332.      MOV     SI,OFFSET ROOT  ;get * * ROOT * *                   djm
  1333. G11:
  1334.      MOV     CX,26           ;                                   djm
  1335.      REPZ    MOVSB           ;                                   djm
  1336.      mov     si,offset HDNG1   ;Print main heading
  1337.      call    show_line
  1338.      mov     si,offset HDNG2   ;Print column 1 heading
  1339.      call    show_line
  1340.      CMP     WORD PTR C2LNK,0
  1341.      JZ      G2              ;If not 2 columns
  1342.      mov     si,offset SPACES-5 ;Print 5 spaces
  1343.      call    show_line
  1344.      mov     si,offset HDNG2   ;Print column 2 heading
  1345.      call    show_line
  1346. G2:  mov     si,offset CRLF    ;Start a new line
  1347.      call    show_line
  1348.      RET
  1349. PRTHDNG ENDP
  1350.  
  1351. PRTDRVR PROC    NEAR         ;Driver routine
  1352.      MOV     BX,C1LNK
  1353.      OR      BX,BX           ;more to print?
  1354.      JZ      H2              ; no, return
  1355.      MOV     AX,[BX]
  1356.      MOV     C1LNK,AX
  1357.      CALL    PRTDTL          ;print column one
  1358.      MOV     BX,C2LNK
  1359.      OR      BX,BX
  1360.      JZ      H1              ;If no column 2 entry
  1361.      mov     si,offset SPACES-5 ;print 5 spaces
  1362.      call    show_line
  1363.      MOV     AX,[BX]
  1364.      MOV     C2LNK,AX
  1365.      CALL    PRTDTL          ;print column two
  1366. H1:  mov     si,offset CRLF
  1367.      call    show_line
  1368.      CMP     PSEFLG,0        ;Check for pause option
  1369.      JZ      PRTDRVR         ;Nope, continue
  1370.      DEC     LINCNT          ;Decrement line counter
  1371.      JNZ     PRTDRVR         ;If page not full?
  1372.      MOV     LINCNT,LPERSCR-2 ;Reset to # lines/screen
  1373.      mov     si,offset PSEMSG  ;Display pause message.
  1374.      call    show_line
  1375.      MOV     ah,0            ;Specify input function
  1376.      int     67h              ;Wait for key press
  1377.      mov     si,offset CRLF    ;Set to new line
  1378.      call    show_line
  1379.      JMP     PRTDRVR         ;Go do the next line
  1380. H2:  RET
  1381. PRTDRVR ENDP
  1382.  
  1383. PRTDTL  PROC    NEAR    ;Prints file.ext, size, date & time
  1384.      MOV     AL,[BX][0AH]    ;get file.ext separator             djm
  1385.      CMP     AL,'-'          ;see if minus inserted              djm
  1386.      JNZ     SHORT I0        ;not a Dir entry                    djm
  1387.      MOV     BYTE PTR [BX][0AH],' '  ;clear minus sign           djm
  1388.      OR      DIRSW,1         ;set switch on                      djm
  1389. I0:  MOV     CX,1+SIZE NAM+SIZE EXT
  1390.      SUB     DI,DI           ;DI <- 0
  1391. I1:  mov     al,[BX+DI].NAM
  1392.      call    show_char
  1393.      INC     DI              ;point to next char.
  1394.      LOOP    I1              ;go do next char.
  1395.      CMP     DIRSW,1         ;see if this is directory entry     djm
  1396.      JNZ     I11             ;no                                 djm
  1397.      mov     si,offset SPACES-8 ;print 8 spaces instead of size    djm
  1398.      call    show_line
  1399.      JMP     SHORT I12
  1400. I11: PUSH    BX              ;save entry base
  1401.      MOV     SI,[BX].SZL     ;SI <- low size
  1402.      MOV     DI,[BX].SZH     ;DI <- high size
  1403.      CALL    PRINTDD         ;Print size
  1404.      POP     BX              ;restore entry base
  1405. I12: mov     si,offset SPACES-2 ;print 2 spaces
  1406.      call    show_line
  1407.      MOV     AX,[BX].DTE     ;AX <- packed date
  1408.      CALL    PRTDTE
  1409.      mov     si,offset SPACES-2 ;print 2 spaces
  1410.      call    show_line
  1411.      MOV     AX,[BX].TME     ;AX <- packed time
  1412.      CALL    PRTTME
  1413.      CMP     DIRSW,1         ;see if switch on                   djm
  1414.      JNZ     I2              ;no                                 djm
  1415.      MOV     DIRSW,0         ;shut off switch                    djm
  1416. I2:  RET
  1417. PRTDTL  ENDP
  1418.  
  1419. PRINTDD PROC    NEAR         ;Prints a 32 bit integer in DI:SI
  1420.      XOR     AX,AX           ;Zero out the
  1421.      MOV     BX,AX           ; working
  1422.      MOV     BP,AX           ; registers.
  1423.      MOV     CX,32           ;# bits of precision
  1424. J1:  SHL     SI,1
  1425.      RCL     DI,1
  1426.      XCHG    BP,AX
  1427.      CALL    J6
  1428.      XCHG    BP,AX
  1429.      XCHG    BX,AX
  1430.      CALL    J6
  1431.      XCHG    BX,AX
  1432.      ADC     AL,0
  1433.      LOOP    J1
  1434.      MOV     CX,1710H        ;5904 ?
  1435.      MOV     AX,BX
  1436.      CALL    J2
  1437.      MOV     AX,BP
  1438. J2:  PUSH    AX
  1439.      MOV     DL,AH
  1440.      CALL    J3
  1441.      POP     DX
  1442. J3:  MOV     DH,DL
  1443.      SHR     DL,1            ;Move high
  1444.      SHR     DL,1            ; nibble to
  1445.      SHR     DL,1            ; the low
  1446.      SHR     DL,1            ; position.
  1447.      CALL    J4
  1448.      MOV     DL,DH
  1449. J4:  AND     DL,0FH          ;Mask low nibble
  1450.      JZ      J5              ;If not zero
  1451.      MOV     CL,0
  1452. J5:  DEC     CH
  1453.      AND     CL,CH
  1454.      OR      DL,'0'          ;Fold in ASCII zero
  1455.      SUB     DL,CL
  1456.      push    ax
  1457.      mov     al,dl
  1458.      call    show_char
  1459.      pop     ax
  1460.      RET                     ;Exit to caller
  1461. PRINTDD ENDP
  1462.  
  1463. J6   PROC    NEAR
  1464.      ADC     AL,AL
  1465.      DAA
  1466.      XCHG    AL,AH
  1467.      ADC     AL,AL
  1468.      DAA
  1469.      XCHG    AL,AH
  1470.      RET
  1471. J6   ENDP
  1472.  
  1473. PRTDTE  PROC    NEAR    ;Print packed date in AX as MM/DD/YY
  1474.      OR      AX,AX
  1475.      JNZ     K1              ;If date <> 0
  1476.      mov     si,offset SPACES-8 ;Print 8 spaces
  1477.      call    show_line
  1478.      RET
  1479. K1:  PUSH    AX
  1480.      AND     AX,MASK P_MO    ;Mask the month,
  1481.      MOV     CL,P_MO         ; set shift count,
  1482.      SHR     AX,CL           ; right justify, &
  1483.      CALL    PRTBCD          ; print it.
  1484.      mov     al,'/'
  1485.      call    show_char
  1486.      POP     AX
  1487.      PUSH    AX
  1488.      AND     AX,MASK P_DY    ;Mask the day &
  1489.      CALL    PRTBCD          ; print it.
  1490.      mov     al,'/'
  1491.      call    show_char
  1492.      POP     AX
  1493.      AND     AX,MASK P_YR    ;Mask the year,
  1494.      MOV     CL,P_YR         ; set shift count,
  1495.      SHR     AX,CL           ; right justify,
  1496.      ADD     AX,80           ; add in year bias, &
  1497.                                 ; print it.
  1498.      call    prtbcd
  1499.      ret
  1500. PRTDTE  ENDP
  1501.  
  1502. PRTBCD proc near
  1503.      push    ax
  1504.      AAM                     ;Convert AL to BCD
  1505.      OR      AX,'00'         ;Convert to ASCII
  1506.      PUSH    AX
  1507.      mov     al,AH      ;High order digit
  1508.      call    show_char
  1509.      POP     AX
  1510.      call    show_char
  1511.      pop     ax
  1512.      RET
  1513. PRTBCD  ENDP
  1514.  
  1515. PRTTME  PROC    NEAR    ;Print packed time in AX as HH:MM
  1516.      OR      AX,AX
  1517.      JNZ     L1
  1518.      mov     si,offset SPACES-5 ;Print 5 spaces
  1519.      call    show_line
  1520.      RET
  1521. L1:  PUSH    AX
  1522.      AND     AX,MASK P_HR    ;Mask the hours,
  1523.      MOV     CL,P_HR         ; set shift count,
  1524.      SHR     AX,CL           ; right justify, &
  1525.      CALL    PRTBCD          ; print it.
  1526.      mov     al,':'
  1527.      call    show_char
  1528.      POP     AX
  1529.      AND     AX,MASK P_MI    ;Mask the minutes,
  1530.      MOV     CL,P_MI         ; set shift count,
  1531.      SHR     AX,CL           ; right justify, &
  1532.      CALL    PRTBCD          ; print it.
  1533.      RET
  1534. PRTTME  ENDP
  1535.  
  1536. PRTNFLS PROC    NEAR         ;print number of files
  1537.      MOV     SI,NBRFILS      ;get # of files
  1538.      XOR     DI,DI           ;zero high order
  1539.      CALL    PRINTDD         ;Print # of files
  1540.      mov     si,offset HDNG3
  1541.      call    show_line
  1542.      MOV     SI,TOTL         ;set up total for print             djm
  1543.      MOV     DI,TOTH         ;                                   djm
  1544.      CALL    PRINTDD         ;print total space used by dir      djm
  1545.      mov     si,offset HDNG5 ;                                   djm
  1546.      call    show_line
  1547.      MOV     SI,LOSIZE       ;free space                         djm
  1548.      MOV     DI,HISIZE       ;                                   djm
  1549.      CALL    PRINTDD         ;print free space                   djm
  1550.      mov     si,offset HDNG6 ;                                   djm
  1551.      call    show_line
  1552.      RET
  1553. PRTNFLS ENDP
  1554. ;
  1555. ; storage for directory entries
  1556. ;   please note - 256 entries is more than enough for anything
  1557. ;   on my system -- but if you've got directories with more entries
  1558. ;   please increase the space.
  1559. ;
  1560.         EVEN
  1561. DIRBUF  DIRNTRY 256 dup(<>)  ;Buffer for directory entries
  1562. ;
  1563. ; storage for a local stack
  1564.              dw 150 dup(0)
  1565. stacktop     label word
  1566.  
  1567. ;
  1568. ; This procedure initializes the new keyboard interupt vectors
  1569. ;
  1570. bad_intr db 'MDIR cannot be installed -- its interrupt'
  1571.          db ' vectors are already in use.$'
  1572. SWAP_VECTORS  proc     near
  1573.      push     ds              ;Set up the
  1574.      xor      ax,ax           ; stack for a
  1575.      push     ax              ; return to DOS.
  1576.  
  1577.      push     cs
  1578.      pop      ds              ; set up DS
  1579.      push     cs
  1580.      pop      es              ; and ES to point to this section
  1581.  
  1582.      mov      di,80h          ; read the command line
  1583.      mov      cl,es:[di]
  1584.      xor      ch,ch           ; clear the high byte
  1585.      cmp      cl,2
  1586.      jb       one_monitor     ; if no command line
  1587.      mov      al,' '          ; Set up to scan for first non-blank
  1588.      inc      di              ; Set DI to PC-DOS parameter pointer
  1589. repe          scasb           ; Scan while blanks
  1590.      jz       one_monitor     ; if we've scanned everything
  1591.      mov      al,es:[di-1]    ; get the first non-blank byte
  1592.      cmp      al,'2'          ; are there two monitors?
  1593.      jne      one_monitor
  1594.      mov      two_screens,1   ; two monitors specified, so set the flag
  1595.      mov      permpse,0       ; don't pause unless told to do so
  1596.  
  1597. one_monitor:
  1598.      mov      ax,0
  1599.      mov      es,ax           ;Clear esp. for Dos 3.0 bug
  1600.      push     es              ; save es
  1601.  
  1602.      mov      ah,35h          ; get the address if Int 67h
  1603.      mov      al,67h
  1604.      int      21h
  1605.      mov      ax,es
  1606.      cmp      ax,0
  1607.      pop      es               ; restore the 0'd ES
  1608.      jne      bad_exit         ;get out if the int is already used
  1609.  
  1610.      mov      ah,35h           ; get the address of the keyboard interrupt
  1611.      mov      al,16h                    ; keyboard function
  1612.      int      21h                       ; get interrupt vector
  1613.      mov      word ptr ROM_KB_INT,bx    ; save the offset
  1614.      mov      word ptr ROM_KB_INT[2],es ; and the segment
  1615.  
  1616.      mov      ah,25h           ; reset the keyboard interrupt
  1617.      mov      al,16h
  1618.      push     cs
  1619.      pop      ds                        ; DS:DX point to this routine
  1620.      mov      dx,offset MDIR_INT
  1621.      int      21h                       ; set interrupt vector
  1622.  
  1623.      mov      ah,25h           ; and reset Int 67h to point to the
  1624.      mov      al,67h           ; old interrupt code
  1625.      mov      dx, word ptr ROM_KB_INT
  1626.      mov      bx, word ptr ROM_KB_INT[2]
  1627.      mov      ds,bx                     ; DS:DX point to the new interrupt
  1628.      int      21h                       ; set interrupt vector
  1629.  
  1630.      int      11h                       ; get the equipment flag
  1631.      mov      bx,ax                     ; save a copy of the flags
  1632.      and      bl,1                      ; are there any floppy disk drives?
  1633.      cmp      bl,1
  1634.      jne      stay_res
  1635.      and      al,11000000b              ; mask the count bits
  1636.      mov      cl,6
  1637.      shr      al,cl                     ; get the count
  1638.      inc      al                        ; and set it so that 1 = 1 drive
  1639.      mov      cs:MAXDRIVE,al            ; and save the number of floppy drives
  1640.                                         ; for future reference
  1641.  
  1642. stay_res:
  1643.      mov      dx,offset bad_intr        ; End of new resident program
  1644.      int      27h                       ; Terminate but stay resident
  1645.  
  1646. bad_exit:                               ; whoops, something ain't kosher, so
  1647.      mov      ah,9                      ; print error message
  1648.      mov      dx,offset bad_intr
  1649.      int      21h
  1650.      ret                                ; return to DOS
  1651. SWAP_VECTORS     endp
  1652. CODE_SEG     ends
  1653.      end     BEGIN
  1654. ;
  1655.